const PENDING = "pending";
const FULFILLED = "fulfilled";
const REJECTED = "rejected";

// 底层逻辑就是看x是不是一个promise？ 是promise就看这个promise是成功还是失败，如果不是直接调用resolve传递给p2
function resolvePromise(p2, x, resolve, reject) {
  // 用x来决定是走p2的 resolve 还是 reject
  // 而是要考虑我的promise和别人的promise 能兼容
  if (p2 === x) {
    return reject(
      new TypeError(
        "[TypeError: Chaining cycle detected for promise #<Promise>] MY"
      )
    );
  }
  if ((typeof x === "object" && x !== null) || typeof x === "function") {
    let called = false;
    try {
      let then = x.then;
      if (typeof then === "function") {
        // 用法上一次获取到的then 来调用，而不是采用在此获取的方式

        then.call(
          x,
          (y) => {
            if (called) return;
            called = true;
            process.nextTick(() => {
              resolvePromise(p2, y, resolve, reject);
            });
          },
          (r) => {
            if (called) return;
            called = true;
            reject(r);
          }
        );
        //
      } else {
        resolve(x); //  {a:1}
      }
    } catch (e) {
      if (called) return;
      called = true;
      reject(e);
    }
  } else {
    resolve(x);
  }
}
class Promise {
  constructor(executor) {
    this.status = PENDING;
    this.value = undefined;
    this.reason = undefined;
    this.onResolvedCallbacks = [];
    this.onRejectedCallbacks = [];
    const resolve = (value) => {
      if (value instanceof Promise) {
        // 只关系自己的promise
        return value.then(resolve, reject); // 如果是promise就不停的递归操作
      }
      if (this.status === PENDING) {
        this.status = FULFILLED;
        this.value = value;
        this.onResolvedCallbacks.forEach((fn) => fn());
      }
    };
    const reject = (reason) => {
      if (this.status === PENDING) {
        this.status = REJECTED;
        this.reason = reason;
        this.onRejectedCallbacks.forEach((fn) => fn());
      }
    };
    try {
      executor(resolve, reject);
    } catch (e) {
      reject(e);
    }
  }
  then(onFulfilled, onRejected) {
    onFulfilled =
      typeof onFulfilled === "function" ? onFulfilled : (data) => data;
    onRejected =
      typeof onRejected === "function"
        ? onRejected
        : (err) => {
            throw err;
          };
    let p2 = new Promise((resolve, reject) => {
      if (this.status === FULFILLED) {
        // ...
        process.nextTick(() => {
          try {
            let x = onFulfilled(this.value);
            resolvePromise(p2, x, resolve, reject);
          } catch (e) {
            console.log(e);
            reject(e);
          }
        });
      }
      if (this.status === REJECTED) {
        // ...
        process.nextTick(() => {
          try {
            let x = onRejected(this.reason);
            resolvePromise(p2, x, resolve, reject);
          } catch (e) {
            reject(e);
          }
        });
      }
      if (this.status === PENDING) {
        // 如果是pending状态，意味着没有更改状态
        this.onResolvedCallbacks.push(() => {
          // ...
          process.nextTick(() => {
            try {
              let x = onFulfilled(this.value);
              resolvePromise(p2, x, resolve, reject);
            } catch (e) {
              reject(e);
            }
          });
        });
        this.onRejectedCallbacks.push(() => {
          // ...
          process.nextTick(() => {
            try {
              let x = onRejected(this.reason);
              resolvePromise(p2, x, resolve, reject);
            } catch (e) {
              reject(e);
            }
          });
        });
      }
    });

    return p2;
  }
  catch(onRejected) {
    return this.then(null, onRejected);
  }
}
Promise.resolve = function (value) {
  return new Promise((resolve, reject) => {
    resolve(value);
  });
};
Promise.reject = function (error) {
  return new Promise((resolve, reject) => {
    reject(error);
  });
};
Promise.deferred = function () {
  let dfd = {};
  dfd.promise = new Promise((resolve, reject) => {
    dfd.resolve = resolve;
    dfd.reject = reject;
  });
  return dfd;
};
Promise.all = function (promises) {
  return new Promise((resolve, reject) => {
    const results = [];
    let times = 0;
    promises.forEach((val, index) => {
      Promise.resolve(val).then((result) => {
        results[index] = result; // 保证顺序11对应
        if (++times === promises.length) {
          resolve(results);
        }
      }, reject);
    });
  });
};

Promise.race = function (promises) {
  return new Promise((resolve, reject) => {
    const results = [];
    let times = 0;
    promises.forEach((val, index) => {
      Promise.resolve(val).then(resolve, reject);
    });
  });
};

module.exports = Promise;

// npm install promises-aplus-tests -g
